﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ToolWindowViewModel.cs" company="Mar3ek">
//   http://mar3ek.wordpress.com
// </copyright>
// <summary>
//   Tool windows view model
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Mar3ek.HouseLight
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Input;
    using LighthouseNET;
    using MessageBox = System.Windows.MessageBox;

    /// <summary>
    /// Tool windows view model
    /// </summary>
    public partial class ToolWindowViewModel : INotifyPropertyChanged, IDisposable
    {
        #region Fields

        private readonly Window _mainWindow;

        /// <summary>
        /// The API instance to use
        /// </summary>
        private readonly LighthouseAPI _api;

        /// <summary>
        /// The refresh command
        /// </summary>
        private readonly ICommand _refreshCommand;

        /// <summary>
        /// The currently selected project
        /// </summary>
        private Project _selectedProject;

        /// <summary>
        /// Selected tab index
        /// </summary>
        private int _selectedTabIndex;

        /// <summary>
        /// Whether this instance has been disposed
        /// </summary>
        private bool _disposed;

        private bool _isMembersEnabled = true;

        private ObservableCollection<User> _users; 

        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="ToolWindowViewModel"/> class.
        /// </summary>
        /// <param name="win">
        /// The main window.
        /// </param>
        /// <param name="api">
        /// The API instance.
        /// </param>
        public ToolWindowViewModel(Window win, LighthouseAPI api)
        {
            _mainWindow = win;
            _api = api;

            try
            {
                Projects = new ObservableCollection<Project>(_api.GetProjects());
            }
            catch (Exception)
            {
                MessageBox.Show("Unable to retrieve projects for the specified login credentials.", "HouseLight", MessageBoxButton.OK, MessageBoxImage.Error);
            }

            if (_projects.Count > 0)
            {
                SelectedProject = _projects[0];
            }

            _filterCommand = new RelayCommand(FilterAction, o => true);
            _newTicketCommand = new RelayCommand(NewTicketAction, o => true);
            _modifyCommand = new RelayCommand(ModifyTicketAction, o => true);
            _deleteCommand = new RelayCommand(DeleteTicketAction, o => true);
            _nextPageCommand = new RelayCommand(NextPage, o => true);
            _prevPageCommand = new RelayCommand(PrevPage, o => true);
            _showTicketHistoryCommand = new RelayCommand(o => IsHistoryViewOpen = true, o => true);

            _newMilestoneCommand = new RelayCommand(NewMilestoneAction, o => true);
            _modifyMilestoneCommand = new RelayCommand(ModifyMilestoneAction, o => true);
            _deleteMilestoneCommand = new RelayCommand(DeleteMilestoneAction, o => true);
            _showMilestoneTicketsCommand = new RelayCommand(ShowMilestoneTicketsAction, o => true);
            _showMilestoneOpenTicketsCommand = new RelayCommand(ShowMilestoneOpenTicketsAction, o => true);

            _newMessageCommand = new RelayCommand(NewMessageAction, o => true);
            _newCommentCommand = new RelayCommand(NewCommentAction, o => true);
            _modifyMessageCommand = new RelayCommand(ModifyMessageAction, o => true);
            _deleteMessageCommand = new RelayCommand(DeleteMessageAction, o => true);

            _newBinCommand = new RelayCommand(NewBinAction, o => true);
            _modifyBinCommand = new RelayCommand(ModifyBinAction, o => true);
            _deleteBinCommand = new RelayCommand(DeleteBinAction, o => true);

            _refreshCommand = new RelayCommand(RefreshAction, o => true);
        }

        /// <summary>
        /// Finalizes an instance of the <see cref="ToolWindowViewModel"/> class. 
        /// <see cref="ToolWindowViewModel"/> is reclaimed by garbage collection.
        /// </summary>
        ~ToolWindowViewModel()
        {
            DisposeObject(false);
        }

        /// <summary>
        /// Occurs when a property value changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Gets the projects.
        /// </summary>
        /// <value>
        /// The projects.
        /// </value>
        public ObservableCollection<Project> Projects
        {
            get
            {
                return _projects;
            }

            private set 
            { 
                _projects = value;
                OnPropertyChanged(new PropertyChangedEventArgs("Projects"));
            }
        }

        /// <summary>
        /// Gets or sets the selected project.
        /// </summary>
        /// <value>
        /// The selected project.
        /// </value>
        public Project SelectedProject
        {
            get
            {
                return _selectedProject;
            }

            set
            {
                _selectedProject = value;

                RefreshTickets();
                RefreshMilestones();
                RefreshMessages();
                RefreshBins();
                RefreshUsers();

                SearchKeywords.Clear();

                foreach (var state in _selectedProject.TicketStates)
                {
                    SearchKeywords.Add(string.Format("state:{0}", state));
                }
                
                OnPropertyChanged(new PropertyChangedEventArgs("SelectedProject"));
            }
        }

        private void RefreshUsers()
        {
            var t = new Thread(() =>
            {
                try
                {
                    var memberships = new List<Membership>(_api.GetProjectMemberships(_selectedProject.Id));
                    Users = new ObservableCollection<User>(from m in memberships select m.User);
                }
                catch (Exception)
                {
                    IsMembersEnabled = false;
                }
            }) { IsBackground = true, Name = "Refresh users thread" };
            t.Start();
        }

        /// <summary>
        /// Gets or sets the index of the selected tab.
        /// </summary>
        /// <value>
        /// The index of the selected tab.
        /// </value>
        public int SelectedTabIndex
        {
            get
            {
                return _selectedTabIndex;
            }

            set
            {
                _selectedTabIndex = value;
                OnPropertyChanged(new PropertyChangedEventArgs("SelectedTabIndex"));
            }
        }

        /// <summary>
        /// Gets the refresh command
        /// </summary>
        public ICommand RefreshCommand
        {
            get { return _refreshCommand; }
        }

        public ObservableCollection<User> Users
        {
            get
            {
                return _users;
            }

            set
            {
                _users = value;
                OnPropertyChanged(new PropertyChangedEventArgs("Users"));
            }
        }

        public bool IsMembersEnabled
        {
            get
            {
                return _isMembersEnabled;
            }

            set
            {
                _isMembersEnabled = value;
                OnPropertyChanged(new PropertyChangedEventArgs("IsMembersEnabled"));
            }
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            DisposeObject(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Raises the <see cref="PropertyChanged"/> event.
        /// </summary>
        /// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
        private void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, e);
            }
        }

        /// <summary>
        /// Disposes the object.
        /// </summary>
        /// <param name="disposing">if set to <c>true</c> [disposing].</param>
        private void DisposeObject(bool disposing)
        {
            if (_disposed)
            {
                return;
            }

            if (disposing)
            {
                _api.Dispose();
            }

            // Dispose unmanaged resources.
            _disposed = true;
        }

        /// <summary>
        /// Refreshes the data from server.
        /// </summary>
        /// <param name="parameter">The parameter.</param>
        private void RefreshAction(object parameter)
        {
            FilterKeyword = string.Empty;
            RefreshTickets();
            RefreshMilestones();
            RefreshMessages();
            RefreshBins();
            RefreshUsers();
        }
    }
}
